﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xn;
using xnv;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;

namespace zdjecia
{
    class KinectZdjecia
    {
        #region zmienne

        Context _context;
        SessionManager _session;
        public SwipeDetector _swipe;
        Thread _kamera;

        DepthGenerator depth;
        Bitmap bitmap;
        public Bitmap b2;
        private int[] histogram;

        Boolean _active = false;
        String _xml;

        #endregion

        #region zdarzenia

        public delegate void SwipeLeftHandler(object sender, HandPositionEventArgs e);
        public event SwipeLeftHandler SwipeLeft;

        public delegate void SwipeRightHandler(object sender, HandPositionEventArgs e);
        public event SwipeRightHandler SwipeRight;

        public delegate void ImageUpdatedHandler(object sender, HandPositionEventArgs e);
        public event ImageUpdatedHandler ImageUpdated;

        #endregion

        public void Initialize()
        {
            System.Console.WriteLine("podnieś ręke");

            _active = true;
            _context = new Context(_xml);

            this.depth = _context.FindExistingNode(NodeType.Depth) as DepthGenerator;
            if (this.depth == null)
            {
                throw new Exception("Viewer must have a depth node!");
            }

            this.histogram = new int[this.depth.GetDeviceMaxDepth()];

            MapOutputMode mapMode = this.depth.GetMapOutputMode();
            this.bitmap = new Bitmap((int)mapMode.nXRes, (int)mapMode.nYRes, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            _session = new SessionManager(_context, "RaiseHand", "RaiseHand");
            _session.SessionStart += new SessionManager.SessionStartHandler(sesjaStart);

            _swipe = new SwipeDetector();
            _swipe.SwipeLeft += new SwipeDetector.SwipeLeftHandler(swipeLeft);
            _swipe.SwipeRight += new SwipeDetector.SwipeRightHandler(swipeRight);

            _session.AddListener(_swipe);

            _context.StartGeneratingAll();

            _kamera = new Thread(KameraThread);
            _kamera.IsBackground = true;
            _kamera.Start();
        }

        public KinectZdjecia(String plikxml)
        {
            _xml = plikxml;
        }

        private void sesjaStart(ref Point3D target)
        {
            System.Console.WriteLine("Złapałem");
        }

        public void koniec()
        {
            _active = false;
            while (_kamera.IsAlive) ;
        }

        private unsafe void KameraThread()
        {
            while (_active)
            {
                DepthMetaData depthMD = new DepthMetaData();

                _context.WaitOneUpdateAll(this.depth);
                _session.Update(_context);

                this.depth.GetMetaData(depthMD);

                CalcHist(depthMD);

                lock (this)
                {
                    Rectangle rect = new Rectangle(0, 0, this.bitmap.Width, this.bitmap.Height);
                    BitmapData data = this.bitmap.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

                    ushort* pDepth = (ushort*)this.depth.GetDepthMapPtr().ToPointer();

                    // set pixels
                    for (int y = 0; y < depthMD.YRes; ++y)
                    {
                        byte* pDest = (byte*)data.Scan0.ToPointer() + y * data.Stride;
                        for (int x = 0; x < depthMD.XRes; ++x, ++pDepth, pDest += 3)
                        {
                            byte pixel = (byte)this.histogram[*pDepth];
                            pDest[0] = 0;
                            pDest[1] = pixel;
                            pDest[2] = pixel;
                        }
                    }

                    this.bitmap.UnlockBits(data);
                }

                b2 = new Bitmap(bitmap);

                ImageUpdated(this, new HandPositionEventArgs(0, 0));
            }

            _session.EndSession();

        }

        private void swipeLeft(float x, float y)
        {
            System.Console.WriteLine("Lewo");
            SwipeLeft(this, new HandPositionEventArgs(x, y));
        }

        private void swipeRight(float x, float y)
        {
            System.Console.WriteLine("Prawo");
            SwipeRight(this, new HandPositionEventArgs(x, y));
        }

        private unsafe void CalcHist(DepthMetaData depthMD)
        {
            // reset
            for (int i = 0; i < this.histogram.Length; ++i)
                this.histogram[i] = 0;

            ushort* pDepth = (ushort*)depthMD.DepthMapPtr.ToPointer();

            int points = 0;
            for (int y = 0; y < depthMD.YRes; ++y)
            {
                for (int x = 0; x < depthMD.XRes; ++x, ++pDepth)
                {
                    ushort depthVal = *pDepth;
                    if (depthVal != 0)
                    {
                        this.histogram[depthVal]++;
                        points++;
                    }
                }
            }

            for (int i = 1; i < this.histogram.Length; i++)
            {
                this.histogram[i] += this.histogram[i - 1];
            }

            if (points > 0)
            {
                for (int i = 1; i < this.histogram.Length; i++)
                {
                    this.histogram[i] = (int)(256 * (1.0f - (this.histogram[i] / (float)points)));
                }
            }
        }

        #region ustawienie_parametrow

        public void setDuration(uint x)
        {
            _swipe.Duration = x;
        }

        public void setMinimumVelocity(float x)
        {
            _swipe.MinimumVelocity = x;
        }

        public void setStedyDuration(uint x)
        {
            _swipe.SteadyDuration = x;
        }

        public void setStedyMaximumVelocity(float x)
        {
            _swipe.SteadyMaximumVelocity = x;
        }

        public void setUseStedy(bool x)
        {
            _swipe.UseSteady = x;
        }

        public void setXAngleThreshold(float x)
        {
            _swipe.XAngleThreshold = x;
        }

        #endregion
    }
}
